﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace Com.Lancetinc.Evs.Helpers
{
    public static class BeanUtil
    {
        public static T Clone<T>(T b)
        {
            return JsonUtil.Parse<T>(JsonUtil.Stringify(b));
        }

        /// <summary>
        /// 克隆一个对象，用于不同类型但是字段相同的bean
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T ChangeType<T>(object obj)
        {
            return JsonUtil.Parse<T>(JsonUtil.Stringify(obj));
        }

        /// <summary>
        /// 拷贝相同名字的字段
        /// </summary>
        /// <param name="source"></param>
        /// <param name="dest"></param>
        /// <param name="filter">对应source字段进行过滤。返回false则不复制</param>
        public static void CopyProperties(object source, object dest, Predicate<PropertyInfo> filter = null)
        {
            var sourceProps = GetProperties(source).Where(x => x.CanRead).ToList();
            var destProps = GetProperties(dest).Where(x => x.CanWrite).ToList();

            foreach (var sourceProp in sourceProps)
            {
                var p = destProps.FirstOrDefault(x => x.Name == sourceProp.Name);
                if (p == null) continue;
                if (filter != null && !filter(p))
                    continue;

                p.SetValue(dest, sourceProp.GetValue(source, null), null);
            }
        }

        /// <summary>
        /// 比较两个对象的对应字段是否一致
        /// </summary>
        /// <param name="o1"></param>
        /// <param name="o2"></param>
        /// <returns></returns>
        public static bool AreEqual(object o1, object o2)
        {
            if (o1 == null)
                return o2 == null;
            if (ReferenceEquals(o1, o2))
                return true;
            if (o1.GetType() != o2.GetType())
                return false;
            var sourceProps = GetProperties(o1).Where(x => x.CanRead).ToList();
            foreach (var pi in sourceProps)
            {
                if (!object.Equals(pi.GetValue(o1), pi.GetValue(o2)))
                {
                    Debug.WriteLine(pi.Name + " not equal");
                    return false;
                }
            }

            return true;
        }

        private static IEnumerable<PropertyInfo> GetProperties(object obj)
        {
            return obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
        }
    }
}
